/** \file    colorate.h
  * \brief   Gives to each segment a unique color near the mean color of part of image it designates.
  * \date    2002
  * \author  Fedor Chelnokov
  * \version $Header: /home/cscom1r4/cvsroot/cs/include/imglib/colorate.h,v 1.1 2004/02/04 14:43:23 cscom1r4 Exp $
  */

#ifndef _colorate_h_
#define _colorate_h_

#include <map>
#include <limits>
#include <cassert>

#include "cinline.h"
#include "math/random.h"

namespace img {

template <class E, class T>
struct segm_data {
	segm_data() {} 
	segm_data(E first_elem) :
		summed_color(first_elem), pcount(1) {}

	T summed_color;
	E color; //typically mean color
	int pcount;
};

///I - image and colored segmentation raster, S - source segmentation raster
///T - type with more capacity than R::elem_type that is used for intermediate summation
///note that ssegm and csegm may be one and the same
template <class I, class S, class T>
void colorate(const I &img, const S &ssegm, I &csegm, T /*unused*/, 	
	size_t random_magnitude=50, ///< the higher the more differently seem colors of distinctive segments
	bool do_not_touch_black_color = false) ///< skips coloration of black regions
{
	size_t w=img.width(), h=img.height();
	assert(w==ssegm.width() && h==ssegm.height());
	assert(w==csegm.width() && h==csegm.height());

	typedef I::elem_type		E;
	typedef E::component_type	EC;

	typedef segm_data<E, T>					sdata;
	typedef std::map<S::elem_type, sdata>	segm_color_t;
	typedef segm_color_t::value_type		segm_color_v;
	typedef std::pair<segm_color_t::iterator, bool>	segm_color_ins_pair;
	segm_color_t segm_color; //segm->color translation table

	//find summed color and pixels count for each segment
	S::const_iterator si = ssegm.begin();
	I::const_iterator ii = img.begin();
	for ( ; si != ssegm.end(); ++si, ++ii) {
		segm_color_v v(*si, sdata(*ii));
		segm_color_ins_pair p(segm_color.insert(v));
		if (!p.second) {
			//insertion not occurred
			p.first->second.summed_color += *ii;
			++p.first->second.pcount;
		}
	}

	typedef std::map<E, int>			used_colors_t; //second int isunused
	typedef used_colors_t::value_type	used_colors_v;
	typedef std::pair<used_colors_t::iterator, bool>	used_colors_ins_pair;
	used_colors_t used_colors; //colors that are already used in colored segmentation

	Urand seq;
	seq.seed(0); //always produce one and the same sequence of numbers

	//mean=sum/count
	segm_color_t::iterator sci = segm_color.begin();
	for ( ; sci != segm_color.end(); ++sci) {
		E &c = sci->second.color;
		c = sci->second.summed_color / sci->second.pcount;

		//may make slight adjustment in color
		size_t i = random_magnitude;
		//assume that EC is of some interger type
		const size_t max = std::numeric_limits<EC>::max();
		bool match = false;
		while (true) {
			while(match || c.is_black()) //zero color forbidden 
			{
				c.b = limit<int>(c.b+seq(i)-i/2, 0, max);
				c.g = limit<int>(c.g+seq(i)-i/2, 0, max);
				c.r = limit<int>(c.r+seq(i)-i/2, 0, max);
				++i;
				match = false;
			} 
			used_colors_v v(c, 0);
			used_colors_ins_pair p(used_colors.insert(v));
			if (p.second) //insertion occurred, color was unused before
				break;
			match = true;
		}
	}

	//output colored segmentation
	I::iterator iii = csegm.begin();
	si = ssegm.begin();
	for ( ; si != ssegm.end(); ++si, ++iii) {
		if (do_not_touch_black_color && (*iii).is_black())
			continue;
		*iii = segm_color[*si].color;
		assert(!((*iii).is_black()));
	}
}

} //namespace img

#endif //_colorate_h_
